﻿#region Header

// Majesty of Omega - The next evolution of macro management space strategy
// 
// Copyright 2007-2009 André Claaßen
// 
// This file is protected by the terms and conditions of the
// Microsoft Community License (Ms-CL 1.1), a copy of which should
// have been distributed along with this software. If not,
// you may find the license information at the following URL:
// 
// http://www.microsoft.com/resources/sharedsource/licensingbasics/communitylicense.mspx

#endregion

#region

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using DesignByContract;
using Majesty_of_Omega.Model.Game;

#endregion

namespace Majesty_of_Omega.Logic.GameConfiguration
{
    /// <summary>
    /// The game manager saves and loads games to the My Games folder of majesty of omega
    /// </summary>
    public class SaveGameManager
    {
        /// <summary>
        /// the standard save game extension
        /// </summary>
        private const string saveGameExtension = ".moosav";

        /// <summary>
        /// this value is true, if the SaveGameManager is operating in unit test modes.
        /// the variable changes the behavior of the MooGameFolder property
        /// </summary>
        private readonly bool _testMode;

        /// <summary>
        /// Initialize a new instance of  <see cref="SaveGameManager"/> class.
        /// </summary>
        public SaveGameManager()
        {
        }

        /// <summary>
        /// Initialize a new instance of <see cref="SaveGameManager"/> class.
        /// </summary>
        /// <param name="testMode">if set to <c>true</c> then the SaveGameManager is operating in unit test mode.</param>
        /// <remarks>the variable changes the behavior of the MooGameFolder property</remarks>
        public SaveGameManager(bool testMode)
        {
            _testMode = testMode;
        }

        /// <summary>
        /// Gets the last games, which resides int the my games folder of majesty of omega
        /// </summary>
        /// <value>The last games.</value>
        public List<SaveGameInfo> LastGamesInMooGameFolder
        {
            get
            {
                var gameInfos = from file in Directory.GetFiles(MooGameFolder)
                                orderby file
                                select LoadGameInfo(file);
                return new List<SaveGameInfo>(gameInfos);
            }
        }

        /// <summary>
        /// Gets the Majesty of Omega save game folder.
        /// </summary>
        /// <value>The moo game folder.</value>
        public string MooGameFolder
        {
            get
            {
                var mooGameFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) +
                                    @"\My Games\Majesty of Omega";
                if (_testMode)
                {
                    mooGameFolder = Path.GetTempPath() + @"\Majesty of Omega";
                }
                if (!Directory.Exists(mooGameFolder))
                {
                    Directory.CreateDirectory(mooGameFolder);
                }
                return mooGameFolder;
            }
        }

        /// <summary>
        /// Saves the specified game to a file stream.
        /// </summary>
        /// <param name="game">The game.</param>
        /// <param name="path">The full path to the file system or a simple file system compatible game name.</param>
        public void Save(SaveGame game, string path)
        {
            Require.IsNotNull(game);
            // Assures the correct save game extension
            path = Path.ChangeExtension(path, saveGameExtension);

            // check, if the path contains a directory. if not, assign the standard
            // save game folder
            var directoryName = Path.GetDirectoryName(path);
            if (string.IsNullOrEmpty(directoryName))
            {
                path = Path.Combine(MooGameFolder, path);
            }

            var gameInfo = new SaveGameInfo
                               {
                                   GameName = Path.GetFileNameWithoutExtension(path),
                                   TurnNumber = game.TurnNumber,
                                   Time = DateTime.Now
                               };
            var fStream = new FileStream(path, FileMode.Create);

            // Create our binary formatter object.
            var formatter = new BinaryFormatter();

            // Serialize our data.
            formatter.Serialize(fStream, gameInfo);
            formatter.Serialize(fStream, game);

            // Close our data file.
            fStream.Close();
        }

        /// <summary>
        /// Loads the specified game from a file
        /// </summary>
        /// <param name="path">The path to the file system.</param>
        /// <returns>the loaded game</returns>
        public SaveGame Load(string path)
        {
            var fStream = new FileStream(path, FileMode.Open);

            // Create our binary formatter object.
            var formatter = new BinaryFormatter();

            // omit the SaveGameInfo
            formatter.Deserialize(fStream);
            var saveGame = (SaveGame) formatter.Deserialize(fStream);

            // Close our data file.
            fStream.Close();
            return saveGame;
        }

        /// <summary>
        /// Loads the game info from the path. 
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns></returns>
        public SaveGameInfo LoadGameInfo(string path)
        {
            var fStream = new FileStream(path, FileMode.Open);

            // Create our binary formatter object.
            var formatter = new BinaryFormatter();

            // retrieve the SaveGameInfo
            var gameInfo = (SaveGameInfo) formatter.Deserialize(fStream);

            // Close our data file.
            fStream.Close();
            return gameInfo;
        }

        /// <summary>
        /// Gets the default filename for a game
        /// </summary>
        /// <param name="saveGame">The save game.</param>
        /// <returns></returns>
        public string GetDefaultFilename(SaveGame saveGame)
        {
            Require.IsTrue(saveGame.TurnNumber >= 0);
            return saveGame.HumanPlayer.EmpireName + " - " + string.Format("{0:D3}", saveGame.TurnNumber);
        }

        /// <summary>
        /// Erases all games in the majesty of omega game folder.
        /// </summary>
        public void EraseAllGamesInMooGameFolder()
        {
            foreach (var file in Directory.GetFiles(MooGameFolder))
                File.Delete(file);
        }

        #region Nested type: SaveGameInfo

        ///<summary>
        /// Info Header of a saved game. This header allows to display essential informations of a game in the Load Game Dialog.
        ///</summary>
        [Serializable]
        public class SaveGameInfo
        {
            /// <summary>
            /// Gets or sets the name of the game without any extension
            /// </summary>
            /// <value>The filename.</value>
            public string GameName { get; set; }

            /// <summary>
            /// Gets or sets the time.
            /// </summary>
            /// <value>The time.</value>
            public DateTime Time { get; set; }

            /// <summary>
            /// Gets or sets the name of the race.
            /// </summary>
            /// <value>The name of the race.</value>
            public string RaceName { get; set; }

            /// <summary>
            /// Gets or sets the turn number.
            /// </summary>
            /// <value>The turn number.</value>
            public int TurnNumber { get; set; }

            /// <summary>
            /// Gets or sets the save game number.
            /// </summary>
            /// <value>The save game number.</value>
            public int SaveGameNumber { get; set; }
        } ;

        #endregion
    }
}